package com.agileai.bpm.service.running;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.mvel2.templates.TemplateRuntime;

import com.agileai.bpm.common.BPMConstants;
import com.agileai.bpm.common.DateTimeUtil;
import com.agileai.bpm.common.VariableInterpreter;
import com.agileai.bpm.domain.define.Activity;
import com.agileai.bpm.domain.define.Activity.ControlType;
import com.agileai.bpm.domain.define.Activity.PropertyKeys;
import com.agileai.bpm.domain.define.Process;
import com.agileai.bpm.domain.define.ProcessVariable;
import com.agileai.bpm.domain.define.Properties;
import com.agileai.bpm.domain.define.Transition;
import com.agileai.bpm.domain.history.ActivityHistory;
import com.agileai.bpm.domain.history.ProcessHistory;
import com.agileai.bpm.domain.running.ActivityInstance;
import com.agileai.bpm.domain.running.ProcessInstance;
import com.agileai.bpm.domain.running.ProcessVariableInstance;
import com.agileai.bpm.domain.running.WorkAttributes;
import com.agileai.bpm.domain.running.WorkItem;
import com.agileai.bpm.interceptor.BaseInterceptor;
import com.agileai.bpm.service.define.DefineService;
import com.agileai.bpm.service.running.ProcessHandle.UserSeqType;
import com.agileai.common.AppConfig;
import com.agileai.common.KeyGenerator;
import com.agileai.domain.DataParam;
import com.agileai.domain.DataRow;
import com.agileai.hotweb.common.BeanFactory;
import com.agileai.hotweb.common.DaoHelper;
import com.agileai.util.DateUtil;
import com.agileai.util.MapUtil;
import com.agileai.util.StringUtil;

public class ProcessEngineImpl implements ProcessEngine{
	private static final Logger loger = Logger.getLogger(ProcessEngineImpl.class);
	
	protected DaoHelper daoHelper = null;
	protected DefineService defineService = null;
	private boolean inited = false;
	private HashMap<String,Process> processeContainer = new HashMap<String,Process>();
	
	public ProcessEngineImpl(){
		
	}
	
	public DataRow getProcessId8InstIdRow(String processCode,String bizRecordId){
		String msgPrefix = "getProcessId8InstId() - ";
		loger.debug(msgPrefix + "-----START");
		
		DataRow result = null;
		String statementId = "wfprocessinstance.getProcessId8InstId";
		DataParam param = new DataParam("processCode",processCode,"bizRecordId",bizRecordId);
		List<DataRow> records = this.daoHelper.queryRecords(statementId, param);
		if (records != null && records.size() > 0){
			result = records.get(0);
		}
		
		loger.debug(msgPrefix + "-----END");
		return result;
	}
	
	public void registryProcess(String processId, Process process) {
		String msgPrefix = "registryProcess() - ";
		loger.debug(msgPrefix + "-----START");
		
		process.setId(processId);
		this.processeContainer.put(processId, process);
		
		loger.debug(msgPrefix + "-----END");
	}
	
	public Process retrieveProcess(String processId) throws RunningException {
		String msgPrefix = "retrieveProcess() - ";
		loger.debug(msgPrefix + "-----START");
		
		Process result = null;
		AppConfig appConfig = BeanFactory.instance().getAppConfig();
		boolean isRuntime = appConfig.getBoolConfig("GlobalConfig", "isRuntime", false);
		if (processeContainer.containsKey(processId) && isRuntime){
			result = processeContainer.get(processId);
		}else{
			result = this.defineService.loadProcess(processId);
		}
		
		loger.debug(msgPrefix + "-----END");
		return result; 
	}
	
	public void createInstance(ProcessInstance processInstance,WorkAttributes workAttributes,boolean skipFirstNode) throws RunningException {
		String msgPrefix = "createInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		insertProcessInstance(processInstance);
		buildProccessVariable(processInstance,workAttributes);
		
		Process process = processInstance.getProcess();
		Activity activity = process.getStartActivity();

		String startActInstId = KeyGenerator.instance().genKey();
		ActivityHistory startActivityHistory = packActivityHistory(activity,startActInstId,processInstance,workAttributes);
		startActivityHistory.setOperaterId(processInstance.getLaucherId());
		startActivityHistory.setOperaterName(processInstance.getLaucherName());
		startActivityHistory.setOperateTime(processInstance.getLaucheTime());
		String launchContent = workAttributes.getAttributes().get(WorkAttributes.OPERA_DESC_KEY);
		if (StringUtil.isNullOrEmpty(launchContent)){
			launchContent = BPMConstants.DEF_LAUNCH_OPERA_DESC;
		}
		startActivityHistory.setContent(launchContent);
		
		processInstance.getActivityHistorys().add(startActivityHistory);
		insertActivityHistory(startActivityHistory);
		
		insertProcVarInstance(processInstance.getVariableInstances());
		
		List<ActivityInstance> nextActivityInstances = evaluateNextActivityInstances(processInstance,activity.getId(),workAttributes);
		
		if (nextActivityInstances.size() == 1){
			ActivityInstance currentActivityInstance = nextActivityInstances.get(0);
			Activity tempActivity = currentActivityInstance.getActivity();
			
			if (Activity.ActTypes.end.equals(tempActivity.getActType())){
				String activityInstanceId = currentActivityInstance.getId();
				ActivityHistory endActivityHistory = packActivityHistory(tempActivity,activityInstanceId
						,processInstance,workAttributes);
				endActivityHistory.setContent(BPMConstants.DEF_FINISH_OPERA_DESC);
				finishProcessInstance(processInstance,endActivityHistory,workAttributes);
			}
			else if (Activity.ActTypes.manual.equals(tempActivity.getActType())){
				if (skipFirstNode){
					String newActInstId = KeyGenerator.instance().genKey();
					currentActivityInstance.setId(newActInstId);
					this.transitInstance(currentActivityInstance, workAttributes);
				}else{
					executeTrans(processInstance, currentActivityInstance, workAttributes);
				}
			}
			else if (Activity.ActTypes.audit.equals(tempActivity.getActType())){
				executeTrans(processInstance, currentActivityInstance, workAttributes);
			}
			else if (Activity.ActTypes.fork.equals(tempActivity.getActType())){
				String newActInstId = KeyGenerator.instance().genKey();
				currentActivityInstance.setId(newActInstId);
				this.transitInstance(currentActivityInstance, workAttributes);					
			}
			else if (Activity.ActTypes.watch.equals(tempActivity.getActType())){
				processInstance.getActivityInstances().put(currentActivityInstance.getCode(), currentActivityInstance);
				String newActInstId = KeyGenerator.instance().genKey();
				insertActivityInstance(currentActivityInstance,workAttributes,newActInstId);
			}
			else if (Activity.ActTypes.invoke.equals(tempActivity.getActType())){
				Activity curActivity = currentActivityInstance.getActivity();
				List<BaseInterceptor> inInterceptorList = curActivity.getInIntercepterList();
				this.executeInterceporList(currentActivityInstance, inInterceptorList,workAttributes);
				this.transitInstance(currentActivityInstance, workAttributes);
			}
			else{
				throw new RunningException("process define is not valid !");	
			}
		}else{
			throw new RunningException("process define is not valid !");
		}
		loger.debug(msgPrefix + "-----END");
	}
	
	
	private void executeTrans(ProcessInstance processInstance,ActivityInstance curActivityInstance,WorkAttributes workAttributes) throws RunningException{
		Activity curActivity = curActivityInstance.getActivity();
		String activityId = curActivity.getId();
		List<DataRow> records = this.getRelUserIdList(activityId);
		for (int j = 0;j < records.size();j++){
			DataRow row = records.get(j);
			String userId = row.getString("USER_ID");
			curActivityInstance.getTargetUserIdList().add(userId);
		}
		
		List<BaseInterceptor> inInterceptorList = curActivity.getInIntercepterList();
		this.executeInterceporList(curActivityInstance, inInterceptorList,workAttributes);

		processInstance.getActivityInstances().put(curActivityInstance.getCode(), curActivityInstance);	
		String newActInstId = KeyGenerator.instance().genKey();
		insertActivityInstance(curActivityInstance,workAttributes,newActInstId);
	}
	
	
	private void buildProccessVariable(ProcessInstance processInstance,WorkAttributes workAttributes){
		Process process = processInstance.getProcess();
		List<ProcessVariable> processVariables = process.getVariableList();
		HashMap<String,ProcessVariableInstance> processVariableInstances = processInstance.getVariableInstances();
		if (processVariables != null && workAttributes != null){
			for (int i=0;i < processVariables.size();i++){
				ProcessVariable processVariable = processVariables.get(i);
				String varCode = processVariable.getCode();
				HashMap<String, String> attributes = workAttributes.getAttributes();
				ProcessVariableInstance processVariableInstance = null;
				if (processVariableInstances.containsKey(varCode)){
					processVariableInstance = processVariableInstances.get(varCode);	
				}else{
					processVariableInstance = new ProcessVariableInstance();
				}
				processVariableInstance.setProcessInstance(processInstance);
				processVariableInstance.setProcessVariable(processVariable);
				

				if (attributes.containsKey(varCode)){
					String value = attributes.get(varCode);
					processVariableInstance.setValue(value);
				}					
				processVariableInstances.put(varCode, processVariableInstance);
			}
		}
	}
	
	private void packProccessProperties(ProcessInstance processInstance,String topKey,HashMap<String,String> configs){
		Properties properties = processInstance.getProperties();
		if (properties == null){
			properties = new Properties();
		}
		properties.put(topKey, configs);
	}

	private HashMap<String,String> getProccessProperty(ProcessInstance processInstance,String topKey){
		HashMap<String,String> result = null;
		Properties properties = processInstance.getProperties();
		if (properties != null){
			result = properties.get(topKey);
		}
		return result;
	}
	
	public void transitInstance(ActivityInstance activityInstance, WorkAttributes workAttributes) throws RunningException {
		String msgPrefix = "transitInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		Activity activity = activityInstance.getActivity();		
		ProcessInstance processInstance = activityInstance.getProcessInstance();
		if (!ProcessInstance.Status.running.equals(processInstance.getStatus())){
			throw new RunningException(processInstance.getId() + " is not in running status !");
		}
		buildProccessVariable(processInstance,workAttributes);
		updateInstance(processInstance);
		
		List<BaseInterceptor> outInterceptorList = activity.getOutIntercepterList();
		this.executeInterceporList(activityInstance,outInterceptorList,workAttributes);
		
		String activityInstanceId = activityInstance.getId();
		ActivityHistory activityHistory = packActivityHistory(activity,activityInstanceId
				,processInstance,workAttributes);
		processInstance.getActivityInstances().remove(activityInstance.getCode());
		processInstance.getActivityHistorys().add(activityHistory);
		
		if (activityInstance.isRealExist()){
			deleteActivityInstance(activityInstance);			
		}
		insertActivityHistory(activityHistory);
		updateProcVarInstance(processInstance.getVariableInstances());
		
		List<ActivityInstance> nextActivityInstances = evaluateNextActivityInstances(processInstance,activity.getId(),workAttributes);
		if (nextActivityInstances.size() == 1){
			ActivityInstance tempActivityInstance = nextActivityInstances.get(0);
			Activity tempActivity = tempActivityInstance.getActivity();
			
			if (Activity.ActTypes.end.equals(tempActivity.getActType())){
				String endActInstId = KeyGenerator.instance().genKey();
				ActivityHistory endActivityHistory = packActivityHistory(tempActivity,endActInstId,processInstance,workAttributes);
				endActivityHistory.setContent(BPMConstants.DEF_FINISH_OPERA_DESC);
				finishProcessInstance(processInstance,endActivityHistory,workAttributes);
				return;
			}
		}
		
		if (Activity.ActTypes.fork.equals(activity.getActType()) && ControlType.OR.equals(activity.getControlType())){
			String actCode = activity.getCode();
			HashMap<String,String> property = this.getProccessProperty(processInstance,  actCode);
			if (property == null){
				property = new HashMap<String,String>();
			}
			property.put(PropertyKeys.forkTransCount, String.valueOf(nextActivityInstances.size()));
			this.packProccessProperties(processInstance, actCode, property);
			this.updateProcessProperties(processInstance);
		}
		
		for (int i=0;i < nextActivityInstances.size();i++){
			ActivityInstance currentActivityInstance = nextActivityInstances.get(i);
			Activity tempActivity = currentActivityInstance.getActivity();
			
			if (Activity.ActTypes.fork.equals(tempActivity.getActType())){
				String newActInstId = KeyGenerator.instance().genKey();
				currentActivityInstance.setId(newActInstId);
				currentActivityInstance.setRealExist(false);
				this.transitInstance(currentActivityInstance, workAttributes);
			}
			else if (Activity.ActTypes.join.equals(tempActivity.getActType())){
				String controlType = tempActivity.getControlType();
				
				if (Activity.ControlType.AND.equals(controlType)){
					String actCode = tempActivity.getCode();
					HashMap<String,String> property = this.getProccessProperty(processInstance,  actCode);
					int triggerCount = 0;
					if (property == null){
						property = new HashMap<String,String>();
					}
					if (property.containsKey(PropertyKeys.triggerCount)){
						triggerCount = Integer.parseInt(property.get(PropertyKeys.triggerCount));
					}
					triggerCount++ ;
					
					if (triggerCount == tempActivity.getInTransitionList().size()){
						property.put(PropertyKeys.triggerCount, String.valueOf(0));
						this.packProccessProperties(processInstance, actCode, property);
						this.updateProcessProperties(processInstance);
						
						String newActInstId = KeyGenerator.instance().genKey();
						currentActivityInstance.setId(newActInstId);
						currentActivityInstance.setRealExist(false);
						this.transitInstance(currentActivityInstance, workAttributes);
					}else{
						property.put(PropertyKeys.triggerCount, String.valueOf(triggerCount));
						this.packProccessProperties(processInstance, actCode, property);
						this.updateProcessProperties(processInstance);
					}
				}
				else if (Activity.ControlType.OR.equals(controlType)){
					String actCode = tempActivity.getCode();
					HashMap<String,String> property = this.getProccessProperty(processInstance,  actCode);
					int triggerCount = 0;
					if (property == null){
						property = new HashMap<String,String>();
					}
					if (property.containsKey(PropertyKeys.triggerCount)){
						triggerCount = Integer.parseInt(property.get(PropertyKeys.triggerCount));
					}
					triggerCount++ ;
					
					
					String macthedForkNodeCode = tempActivity.getMatchedFork();
					HashMap<String,String> forkNodeProperty = this.getProccessProperty(processInstance,  macthedForkNodeCode);
					
					if (forkNodeProperty.get(PropertyKeys.forkTransCount) == null ){
						throw new RunningException("process define is not valid !");	
					}
					int macthedForkCount = Integer.parseInt(forkNodeProperty.get(PropertyKeys.forkTransCount));
					if (triggerCount == macthedForkCount){
						property.put(PropertyKeys.triggerCount, String.valueOf(0));
						this.packProccessProperties(processInstance, actCode, property);
						this.updateProcessProperties(processInstance);
						
						String newActInstId = KeyGenerator.instance().genKey();
						currentActivityInstance.setId(newActInstId);
						currentActivityInstance.setRealExist(false);
						this.transitInstance(currentActivityInstance, workAttributes);
					}else{
						property.put(PropertyKeys.triggerCount, String.valueOf(triggerCount));
						this.packProccessProperties(processInstance, actCode, property);
						this.updateProcessProperties(processInstance);
					}
				}
				else if (Activity.ControlType.XOR.equals(controlType)){
					String newActInstId = KeyGenerator.instance().genKey();
					currentActivityInstance.setId(newActInstId);
					currentActivityInstance.setRealExist(false);
					this.transitInstance(currentActivityInstance, workAttributes);
				}else{
					throw new RunningException("process define is not valid !");	
				}
			}			
			else if (Activity.ActTypes.watch.equals(tempActivity.getActType())){
				processInstance.getActivityInstances().put(currentActivityInstance.getCode(), currentActivityInstance);
				String newActInstId = KeyGenerator.instance().genKey();
				insertActivityInstance(currentActivityInstance,workAttributes,newActInstId);
			}
			else if (Activity.ActTypes.invoke.equals(tempActivity.getActType())){
				Activity curActivity = currentActivityInstance.getActivity();
				List<BaseInterceptor> inInterceptorList = curActivity.getInIntercepterList();
				this.executeInterceporList(currentActivityInstance, inInterceptorList,workAttributes);
				
				String newActInstId = KeyGenerator.instance().genKey();
				currentActivityInstance.setId(newActInstId);
				currentActivityInstance.setRealExist(false);
				this.transitInstance(currentActivityInstance, workAttributes);
			}
			else if (Activity.ActTypes.audit.equals(tempActivity.getActType()) || Activity.ActTypes.manual.equals(tempActivity.getActType())){
				executeTrans(processInstance, currentActivityInstance, workAttributes);		
			}
			else{
				throw new RunningException("process define is not valid !");	
			}
		}
		loger.debug(msgPrefix + "-----END");
	}
	
	public List<WorkItem> findWorkItemList(String seq,String type) {
		String msgPrefix = "findTaskItemList() - ";
		loger.debug(msgPrefix + "-----START");
		
		List<WorkItem> result = new ArrayList<WorkItem>();
		DataParam param = new DataParam();
		String sqlNameSpace = "WF_INST_ACTIVITY";
		if (type.equals(UserSeqType.USER_ID)){
			param.put("USER_ID",seq);	
		}else{
			param.put("USER_CODE",seq);
		}
		String statementId = sqlNameSpace+"."+"findActivityInstancesByUserId";
		List<DataRow> taskItemRows = this.daoHelper.queryRecords(statementId, param);
		for (int i=0;i < taskItemRows.size();i++){
			DataRow taskItemRow = taskItemRows.get(i);
			WorkItem taskItem = buildWorkItem(taskItemRow);
			result.add(taskItem);
		}
		
		loger.debug(msgPrefix + "-----END");
		return result;
	}
	
	public boolean isOwnTaskItem(String userId, String processInstanceId, String activityCode) {
		String msgPrefix = "isOwnTaskItem() - ";
		loger.debug(msgPrefix + "-----START");
		
		boolean result = false;
		DataParam param = new DataParam();
		String sqlNameSpace = "WF_INST_ACTIVITY";
		param.put("USER_ID",userId);
		param.put("WFIP_ID",processInstanceId);
		param.put("WFIA_CODE",activityCode);
		String statementId = sqlNameSpace+"."+"findActivityInstancesByConditions";
		List<DataRow> taskItemRows = this.daoHelper.queryRecords(statementId, param);
		if (taskItemRows != null && taskItemRows.size() > 0){
			result = true;
		}
		
		loger.debug(msgPrefix + "-----END");
		return result;
	}
	
	private WorkItem buildWorkItem(DataRow taskItemRow){
		String msgPrefix = "buildTaskItem() - ";
		loger.debug(msgPrefix + "-----START");
		
		WorkItem taskItem = new WorkItem();
		taskItem.setActivityCode(taskItemRow.stringValue("WFA_CODE"));
		taskItem.setTitle(taskItemRow.stringValue("WFIP_TITLE"));
		taskItem.setLaucherId(taskItemRow.stringValue("WFIP_LANCHER_ID"));
		taskItem.setLaucherName(taskItemRow.stringValue("WFIP_LANCHER_NAME"));
		Timestamp lauchTime = taskItemRow.getTimestamp("WFIP_LANCH_TIME");
		taskItem.setLaucheTime(DateUtil.getDateByType(DateUtil.YYMMDDHHMISS_HORIZONTAL,new Date(lauchTime.getTime())));
		taskItem.setProcessId(taskItemRow.stringValue("WFP_ID"));
		taskItem.setProcInstanceId(taskItemRow.stringValue("WFIP_ID"));
		taskItem.setProcInstanceState(taskItemRow.stringValue("WFIP_STATUS"));
		taskItem.setBusinessURL(taskItemRow.stringValue("WFA_BIZ_URL"));
		taskItem.setMobileBizURL(taskItemRow.stringValue("WFA_MBIZ_URL"));
		
		taskItem.setSubmiterId(taskItemRow.stringValue("WFIP_OPERATER_ID"));
		taskItem.setSubmiterName(taskItemRow.stringValue("WFIP_OPERATER_NAME"));
		Timestamp operaTime = taskItemRow.getTimestamp("WFIP_OPERATER_TIME");
		taskItem.setSubmiteTime(DateUtil.getDateByType(DateUtil.YYMMDDHHMISS_HORIZONTAL,new Date(operaTime.getTime())));
		
		taskItem.setActivityName(taskItemRow.stringValue("WFA_NAME"));
		taskItem.setProcessName(taskItemRow.stringValue("WFP_NAME"));
		taskItem.setBusinessId(taskItemRow.stringValue("WFIP_BUSINESS_ID"));
		
		loger.debug(msgPrefix + "-----END");
		return taskItem;
	}
	
	public ProcessInstance retrieveProcessInstance(String processInstanceId) throws RunningException {
		String msgPrefix = "retrieveProcessInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		ProcessInstance processInstance = new ProcessInstance();
		DataParam param = new DataParam();
		String sqlNameSpace = "WF_INST_PROCESS";
		param.put("WFIP_ID",processInstanceId);
		String statementId = sqlNameSpace+"."+"retrieveProcessInstance";
		DataRow processInstanceRow = this.daoHelper.getRecord(statementId, param);
		
		sqlNameSpace = "WF_INST_ACTIVITY";
		param = new DataParam();
		param.put("WFIP_ID",processInstanceId);
		statementId = sqlNameSpace+"."+"findActivityInstances";
		List<DataRow> activityInstances = this.daoHelper.queryRecords(statementId, param);
		
		sqlNameSpace = "WF_INST_VARIABLE";
		param = new DataParam();
		param.put("WFIP_ID",processInstanceId);
		statementId = sqlNameSpace+"."+"findProcVarInstances";
		List<DataRow> procVarInstances = this.daoHelper.queryRecords(statementId, param);		
		
		sqlNameSpace = "WF_HIS_ACTIVITY";
		param = new DataParam();
		param.put("WFIP_ID",processInstanceId);
		statementId = sqlNameSpace+"."+"findActivityHistories";
		List<DataRow> activityHistories = this.daoHelper.queryRecords(statementId, param);
		
		processInstance = buildProcessInstance(processInstanceRow,activityInstances,procVarInstances
				,activityHistories);
		
		loger.debug(msgPrefix + "-----END");
		return processInstance;
	}
	
	private ProcessInstance buildProcessInstance(DataRow instanceRow,List<DataRow> activityInstances,
			List<DataRow> procVarInstances,List<DataRow> activityHistories) throws RunningException{
		String msgPrefix = "buildProcessInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		ProcessInstance result = new ProcessInstance();
		result.setId(instanceRow.stringValue("WFIP_ID"));
		String processURI = instanceRow.stringValue("WFP_ID");
		Process process = this.retrieveProcess(processURI);
		
		result.setProcessId(processURI);
		result.setProcess(process);
		result.setTitle(instanceRow.stringValue("WFIP_TITLE"));
		result.setStatus(instanceRow.stringValue("WFIP_STATUS"));
		result.setLaucherId(instanceRow.stringValue("WFIP_LANCHER_ID"));
		result.setLaucherName(instanceRow.stringValue("WFIP_LANCHER_NAME"));
		Timestamp launchTime = instanceRow.getTimestamp("WFIP_LANCH_TIME");
		result.setLaucheTime(DateUtil.getDateByType(DateUtil.YYMMDDHHMISS_HORIZONTAL
				,new Date(launchTime.getTime())));
		
		result.setOperaterId(instanceRow.stringValue("WFIP_OPERATER_ID"));
		result.setOperaterName(instanceRow.stringValue("WFIP_OPERATER_NAME"));
		Timestamp operateTime = instanceRow.getTimestamp("WFIP_OPERATER_TIME");
		result.setOperateTime(DateUtil.getDateByType(DateUtil.YYMMDDHHMISS_HORIZONTAL
				,new Date(operateTime.getTime())));
		result.setBizRecordId(instanceRow.stringValue("WFIP_BUSINESS_ID"));
		
		String propertiesText = instanceRow.getString("WFIP_PROPERTIES");
		Properties properties  = Properties.fromString(propertiesText);
		result.setProperties(properties);
		
		for (int i=0;i < activityInstances.size();i++){
			DataRow actInstRow = activityInstances.get(i);
			ActivityInstance activityInstance = packActivityInstance(actInstRow, result);
			String code = activityInstance.getCode();
			result.getActivityInstances().put(code, activityInstance);
			activityInstance.setProcessInstance(result);
		}
		for (int i=0;i < procVarInstances.size();i++){
			DataRow procVarInstRow = procVarInstances.get(i);
			ProcessVariableInstance variableInstance = buildVariableInstance(procVarInstRow, result);
			result.getVariableInstances().put(variableInstance.getCode(), variableInstance);
			variableInstance.setProcessInstance(result);
		}
		for (int i=0;i < activityHistories.size();i++){
			DataRow actHisRow = activityHistories.get(i);
			ActivityHistory activityHistory = buildActivityHistory(actHisRow, result);
			result.getActivityHistorys().add(activityHistory);
			activityHistory.setProcessInstanceId(result.getId());
		}
		
		loger.debug(msgPrefix + "-----END");
		return result;
	}
	
	private ActivityInstance packActivityInstance(DataRow actInstRow,ProcessInstance processInstance){
		String msgPrefix = "buildActivityInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		ActivityInstance result = new ActivityInstance();
		result.setId(actInstRow.stringValue("WFIA_ID"));
		String activityCode = actInstRow.stringValue("WFIA_CODE");
		Process process = processInstance.getProcess();
		Activity activity = process.getActivity(activityCode);
		result.setActivity(activity);
		result.setProcessInstance(processInstance);
		result.setBusinessURL(actInstRow.stringValue("WFIA_BIZ_URL"));
		result.setMobileBizURL(actInstRow.stringValue("WFIA_MBIZ_URL"));
		result.setBizdataXML(actInstRow.stringValue("WFIA_ATTRIBUTES"));
		
		loger.debug(msgPrefix + "-----END");
		
		return result;
	}
	
	private ProcessVariableInstance buildVariableInstance(DataRow procVarInstRow,ProcessInstance processInstance){
		String msgPrefix = "buildVariableInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		ProcessVariableInstance result = new ProcessVariableInstance();
		result.setProcessInstance(processInstance);
		ProcessVariable processVariable = new ProcessVariable();
		result.setProcessVariable(processVariable);
		result.setId(procVarInstRow.stringValue("WFIPV_ID"));
		processVariable.setCode(procVarInstRow.stringValue("WFIFV_VARCODE"));
		processVariable.setVarType(procVarInstRow.stringValue("WFIFV_VARTYPE"));
		result.setValue(procVarInstRow.stringValue("WFIFV_VARVALUE"));
		
		loger.debug(msgPrefix + "-----END");
		return result;
	}
	
	private ActivityHistory buildActivityHistory(DataRow actHisRow,ProcessInstance processInstance){
		String msgPrefix = "buildActivityHistory() - ";
		loger.debug(msgPrefix + "-----START");
		
		ActivityHistory result = new ActivityHistory();
		Process process = processInstance.getProcess();
		result.setId(actHisRow.stringValue("WFHA_ID"));
		String activityCode = actHisRow.stringValue("WFIA_CODE");
		Activity activity = process.getActivity(activityCode);
		result.setActivity(activity);
		result.setProcessInstanceId(actHisRow.stringValue("WFIP_ID"));
		result.setActivityInstanceId(actHisRow.stringValue("WFIA_ID"));
		result.setOperaterId(actHisRow.stringValue("WFHA_OPERTER"));
		result.setOperaterName(actHisRow.stringValue("WFHA_OPERTER_NAME"));
		Timestamp operaTimestamp = actHisRow.getTimestamp("WFHA_OPERTE_TIME");
		result.setOperateTime(DateUtil.getDateByType(DateUtil.YYMMDDHHMISS_HORIZONTAL
				,new Date(operaTimestamp.getTime())));
		result.setContent(actHisRow.stringValue("WFHA_CONTENT"));
		String bizDataXML = actHisRow.stringValue("WFHA_ATTRIBUTES");
		WorkAttributes workAttributes = new WorkAttributes();
		workAttributes.initFromXML(bizDataXML);
		result.setWorkAttributes(workAttributes);
		
		loger.debug(msgPrefix + "-----END");
		return result;
	}
	
	public void terminateInstance(String processInstatnceId) throws RunningException {
		String msgPrefix = "terminateInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		ProcessInstance processInstance = retrieveProcessInstance(processInstatnceId);
		
		HashMap<String, ActivityInstance> activityInstances = processInstance.getActivityInstances();
		Iterator<String> keys = activityInstances.keySet().iterator();
		while (keys.hasNext()){
			String key = keys.next();
			ActivityInstance activityInstance = activityInstances.get(key);
			String activityInstanceId = activityInstance.getId();
			Activity activity = activityInstance.getActivity();
			
			WorkAttributes workAttributes = new WorkAttributes();
			workAttributes.addAttribute(WorkAttributes.OPERA_DESC_KEY, ProcessHistory.CompleteMode.terminate);
			
			ActivityHistory activityHistory = packActivityHistory(activity,activityInstanceId
					,processInstance,workAttributes);
			processInstance.getActivityInstances().remove(activityInstance.getCode());
			processInstance.getActivityHistorys().add(activityHistory);

			deleteActivityInstance(activityInstance);
			insertActivityHistory(activityHistory);
		}
		
		String sqlNameSpace = "WF_HIS_PROCESS";
		String statementId = sqlNameSpace+"."+"insertProcessHistory";
		DataParam param = new DataParam();
		ProcessHistory processHistory = new ProcessHistory();
		processHistory = buildProcessHistory(processInstance);
		processHistory.setCompleteMode(ProcessHistory.CompleteMode.terminate);
		packProcessHistoryParam(param, processHistory);
		this.daoHelper.insertRecord(statementId, param);	
		
		sqlNameSpace = "WF_INST_PROCESS";
		statementId = sqlNameSpace+"."+"deleteProcessInstance";
		param = new DataParam();
		param.put("WFIP_ID", processInstance.getId());
		this.daoHelper.deleteRecords(statementId, param);
		
		sqlNameSpace = "WF_INST_VARIABLE";
		statementId = sqlNameSpace+"."+"deleteProcVarInstance";
		param = new DataParam();
		param.put("WFIP_ID", processInstance.getId());
		this.daoHelper.deleteRecords(statementId, param);
		
		loger.debug(msgPrefix + "-----END");
	}
	
	public void updateInstance(ProcessInstance processInstance) throws RunningException {
		String msgPrefix = "updateInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		DataParam param = new DataParam();
		String sqlNameSpace = "WF_INST_PROCESS";
		String statementId = sqlNameSpace+"."+"updateProcessInstance";
		packProcessInstanceParam(param,processInstance);
		this.daoHelper.updateRecord(statementId, param);
		
		loger.debug(msgPrefix + "-----END");
	}
	
	private void updateProcessProperties(ProcessInstance processInstance) throws RunningException {
		String msgPrefix = "updateProcessProperties() - ";
		loger.debug(msgPrefix + "-----START");
		
		DataParam param = new DataParam();
		String sqlNameSpace = "WF_INST_PROCESS";
		String statementId = sqlNameSpace+"."+"updateProcessProperties";
		
		String properties = processInstance.getProperties().toString();
		param.put("WFIP_PROPERTIES",properties);
		param.put("WFIP_ID",processInstance.getId());
		
		this.daoHelper.updateRecord(statementId, param);
		
		loger.debug(msgPrefix + "-----END");
	}
	
	private void insertActivityHistory(ActivityHistory activityHistory){
		String msgPrefix = "insertActivityHistory() - ";
		loger.debug(msgPrefix + "-----START");
		
		String sqlNameSpace = "WF_HIS_ACTIVITY";
		String statementId = sqlNameSpace+"."+"insertActivityHistory";
		DataParam param = new DataParam();
		String hisActId = KeyGenerator.instance().genKey();
		activityHistory.setId(hisActId);
		packActivityHistoryParam(param, activityHistory);
		this.daoHelper.insertRecord(statementId, param);
		
		loger.debug(msgPrefix + "-----END");
	}
	
	private void finishProcessInstance(ProcessInstance processInstance,ActivityHistory endActivityHistory,WorkAttributes workAttributes) throws RunningException{
		String msgPrefix = "finishProcessInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		String sqlNameSpace = "WF_HIS_PROCESS";
		String statementId = sqlNameSpace+"."+"insertProcessHistory";
		DataParam param = new DataParam();
		ProcessHistory processHistory = new ProcessHistory();
		processHistory = buildProcessHistory(processInstance);
		processHistory.setCompleteMode(ProcessHistory.CompleteMode.finish);
		packProcessHistoryParam(param, processHistory);
		this.daoHelper.insertRecord(statementId, param);	
		
		this.insertActivityHistory(endActivityHistory);
		
		sqlNameSpace = "WF_INST_PROCESS";
		statementId = sqlNameSpace+"."+"deleteProcessInstance";
		param = new DataParam();
		param.put("WFIP_ID", processInstance.getId());
		this.daoHelper.deleteRecords(statementId, param);
		
		sqlNameSpace = "WF_INST_VARIABLE";
		statementId = sqlNameSpace+"."+"deleteProcVarInstance";
		param = new DataParam();
		param.put("WFIP_ID", processInstance.getId());
		this.daoHelper.deleteRecords(statementId, param);
		
		loger.debug(msgPrefix + "-----END");
	}
	
	private ProcessHistory buildProcessHistory(ProcessInstance processInstance){
		String msgPrefix = "buildProcessHistory() - ";
		loger.debug(msgPrefix + "-----START");
		
		ProcessHistory result = new ProcessHistory();
		Process process = processInstance.getProcess();
		String id = KeyGenerator.instance().genKey();
		result.setId(String.valueOf(id));
		result.setProcessInstanceId(processInstance.getId());
		result.setProcess(process);
		result.setTitle(processInstance.getTitle());
		result.setLaucherId(processInstance.getLaucherId());
		result.setLaucherName(processInstance.getLaucherName());
		result.setLaucheTime(processInstance.getLaucheTime());
		result.setCompleterId(processInstance.getOperaterId());
		result.setCompleterName(processInstance.getOperaterName());
		result.setCompleteTime(processInstance.getOperateTime());
		result.setBusinessId(processInstance.getBizRecordId());
		
		loger.debug(msgPrefix + "-----END");
		return result;
	}
	
	private void deleteActivityInstance(ActivityInstance activityInstance){
		String msgPrefix = "deleteActivityInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		String sqlNameSpace = "WF_INST_ACTIVITY";
		String statementId = sqlNameSpace+"."+"deleteActivityInstance";
		DataParam param = new DataParam();
		param.put("WFIA_ID",activityInstance.getId());
		this.daoHelper.deleteRecords(statementId, param);
		
		sqlNameSpace = "WF_INST_ACTIVITY";
		statementId = sqlNameSpace+"."+"deletetWorkItemByActInstId";
		DataParam workItemParam = new DataParam();
		workItemParam.put("WFIA_ID",activityInstance.getId());
		this.daoHelper.deleteRecords(statementId, workItemParam);
		
		loger.debug(msgPrefix + "-----END");
	}
	
	private void insertActivityInstance(ActivityInstance activityInstance,WorkAttributes workAttributes,String newActInstId) throws RunningException{
		String msgPrefix = "insertActivityInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		String sqlNameSpace = "WF_INST_ACTIVITY";
		String statementId = sqlNameSpace+"."+"insertActivityInstance";
		DataParam param = new DataParam();
		activityInstance.setId(newActInstId);
		packActivityInstanceParam(param, activityInstance);
		this.daoHelper.insertRecord(statementId, param);	
		
		List<String> targetUserIdList = activityInstance.getTargetUserIdList();
		if (!targetUserIdList.isEmpty()){
			ProcessInstance processInstance = activityInstance.getProcessInstance();
			statementId = sqlNameSpace+"."+"insertWorkItem";
			List<DataParam> paramList = new ArrayList<DataParam>();
			KeyGenerator keyGenerator = KeyGenerator.instance();
			for (int i=0;i < targetUserIdList.size();i++){
				String targetUserId = targetUserIdList.get(i);
				DataParam workItemParam = new DataParam();
				workItemParam.put("WWI_ID",keyGenerator.genKey());
				workItemParam.put("WFIA_ID",newActInstId);
				workItemParam.put("WFIP_ID",processInstance.getId());
				workItemParam.put("USER_ID",targetUserId);
				paramList.add(workItemParam);
			}
			this.daoHelper.batchInsert(statementId, paramList);
		}

		List<String> targetUserCodeList = activityInstance.getTargetUserCodeList();
		if (!targetUserCodeList.isEmpty()){
			ProcessInstance processInstance = activityInstance.getProcessInstance();
			statementId = "SecurityUserQuery.queryUserRecordsByCodes";
			DataParam queryParam = new DataParam();
			String userCodesSyntax = this.buildUserCodeSyntax(targetUserCodeList);
			queryParam.put("userCodes",userCodesSyntax);
			HashMap<String,DataRow> userMap = this.daoHelper.queryRecords("USER_CODE", statementId, queryParam);
			
			List<DataParam> paramList = new ArrayList<DataParam>();
			KeyGenerator keyGenerator = KeyGenerator.instance();
			for (int i=0;i < targetUserCodeList.size();i++){
				String targetUserCode = targetUserCodeList.get(i);
				DataRow row = userMap.get(targetUserCode);
				String targetUserId = row.getString("USER_ID");
				
				DataParam workItemParam = new DataParam();
				workItemParam.put("WWI_ID",keyGenerator.genKey());
				workItemParam.put("WFIA_ID",newActInstId);
				workItemParam.put("WFIP_ID",processInstance.getId());
				workItemParam.put("USER_ID",targetUserId);
				paramList.add(workItemParam);
			}
			statementId = sqlNameSpace+"."+"insertWorkItem";
			this.daoHelper.batchInsert(statementId, paramList);
		}
		loger.debug(msgPrefix + "-----END");
	}
	
	private String buildUserCodeSyntax(List<String> userCodeList){
		StringBuffer buffer = new StringBuffer("'");
		for (int i=0;i < userCodeList.size();i++){
			String userCode = userCodeList.get(i);
			buffer.append(userCode).append("','");
		}
		return buffer.substring(0,buffer.length()-2);
	}
	
	private List<DataRow> getRelUserIdList(String activityId){
		List<DataRow> records = new ArrayList<DataRow>();
		String statementId = "WF_ACTIVITY.getRelUserIdList";
		DataParam queryParam = new DataParam("activityId",activityId);
		records = this.daoHelper.queryRecords(statementId,queryParam);
		return records;
	}
	
	private void insertProcVarInstance(HashMap<String, ProcessVariableInstance> variableInstances){
		String msgPrefix = "insertProcVarInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		String sqlNameSpace = "WF_INST_VARIABLE";
		String statementId = sqlNameSpace+"."+"insertProcVarInstance";
		DataParam param;
		if (variableInstances != null && variableInstances.size() > 0){
			Iterator<String> iter = variableInstances.keySet().iterator();
			while(iter.hasNext()){
				String curVarInstId = KeyGenerator.instance().genKey();
				String key = (String)iter.next();
				ProcessVariableInstance variableInstance = variableInstances.get(key);
				variableInstance.setId(String.valueOf(curVarInstId));
				param = new DataParam();
				packVariableInstanceParam(param, variableInstance);
				this.daoHelper.insertRecord(statementId, param);
			}
		}
		loger.debug(msgPrefix + "-----END");
	}
	
	@SuppressWarnings("rawtypes")
	private void updateProcVarInstance(HashMap<String, ProcessVariableInstance> variableInstances){
		String msgPrefix = "updateProcVarInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		String sqlNameSpace = "WF_INST_VARIABLE";
		String statementId = sqlNameSpace+"."+"updateProcVarInstance";
		DataParam param;
		Iterator iter = variableInstances.keySet().iterator();
		while(iter.hasNext()){
			String key = (String)iter.next();
			ProcessVariableInstance variableInstance = variableInstances.get(key);
			param = new DataParam();
			packVariableInstanceParam(param, variableInstance);
			this.daoHelper.updateRecord(statementId, param);			
		}
		loger.debug(msgPrefix + "-----END");
	}
	
	private void insertProcessInstance(ProcessInstance processInstance){
		String msgPrefix = "insertProcessInstance() - ";
		loger.debug(msgPrefix + "-----START");
		
		DataParam param = new DataParam();
		String sqlNameSpace = "WF_INST_PROCESS";
		String statementId = sqlNameSpace+"."+"insertProcessInstance";
		String id = KeyGenerator.instance().genKey();
		processInstance.setId(id);
		processInstance.setStatus(ProcessInstance.Status.running);
		packProcessInstanceParam(param,processInstance);
		
		this.daoHelper.insertRecord(statementId, param);
		
		statementId = "WF_WORK_DRAFT.retrieveWorkDraft";
		DataParam deleteParam = new DataParam("WFP_ID",processInstance.getProcessId(),"WWD_BIZ_ID",processInstance.getBizRecordId());
		DataRow draftRecord = this.daoHelper.getRecord(statementId, deleteParam);
		if (draftRecord != null && draftRecord.size() > 0){
			statementId = "WF_WORK_DRAFT.deleteWorkDraft";
			this.daoHelper.deleteRecords(statementId, deleteParam);			
		}
		loger.debug(msgPrefix + "-----END");
	}
	
	private void packProcessInstanceParam(DataParam param,ProcessInstance processInstance){
		Process proces = processInstance.getProcess();
		param.put("WFIP_ID", processInstance.getId());
		param.put("WFP_ID", proces.getId());
		param.put("WFIP_TITLE", processInstance.getTitle());
		param.put("WFIP_STATUS", processInstance.getStatus());
		param.put("WFIP_LANCHER_ID", processInstance.getLaucherId());
		param.put("WFIP_LANCHER_NAME", processInstance.getLaucherName());
		param.put("WFIP_LANCH_TIME", DateTimeUtil.getDate(processInstance.getLaucheTime()));
		param.put("WFIP_OPERATER_ID", processInstance.getOperaterId());
		param.put("WFIP_OPERATER_NAME", processInstance.getOperaterName());
		param.put("WFIP_OPERATER_TIME", DateTimeUtil.getDate(processInstance.getOperateTime()));
		param.put("WFIP_BUSINESS_ID", processInstance.getBizRecordId());
	}
	private void packActivityInstanceParam(DataParam param,ActivityInstance activityInstance){
		Activity activity = activityInstance.getActivity();
		ProcessInstance processInstance = activityInstance.getProcessInstance();
		param.put("WFIA_ID", activityInstance.getId());
		param.put("WFA_ID", activity.getId());
		param.put("WFIA_CODE", activity.getCode());
		param.put("WFIP_ID", processInstance.getId());

		String bizURLTemplate = activity.getBusinessURL();
		if (!StringUtil.isNullOrEmpty(bizURLTemplate)){
			String businessURL = VariableInterpreter.replaceVariables(bizURLTemplate, activityInstance);
			param.put("WFIA_BIZ_URL", businessURL);	
		}
		
		String mbizURLTemplate = activity.getMobileBizURL();
		if (!StringUtil.isNullOrEmpty(mbizURLTemplate)){
			String mobileBizURL = VariableInterpreter.replaceVariables(mbizURLTemplate, activityInstance);
			param.put("WFIA_MBIZ_URL", mobileBizURL);	
		}		
		
		String bizdataXML = activityInstance.getBizdataXML();
		if (!StringUtil.isNullOrEmpty(bizdataXML)){
			param.put("WFIA_ATTRIBUTES", bizdataXML);
		}
	}
	private void packVariableInstanceParam(DataParam param,ProcessVariableInstance variableInstance){
		ProcessInstance processInstance = variableInstance.getProcessInstance();
		ProcessVariable processVariable = variableInstance.getProcessVariable();
		param.put("WFIPV_ID", variableInstance.getId());
		param.put("WFIP_ID", processInstance.getId());
		param.put("WFIFV_VARCODE", processVariable.getCode());
		param.put("WFIFV_VARTYPE", processVariable.getVarType());
		param.put("WFIFV_VARVALUE", variableInstance.getValue());
	}	
	private void packActivityHistoryParam(DataParam param,ActivityHistory activityHistory){
		Activity activity = activityHistory.getActivity();
		param.put("WFHA_ID", activityHistory.getId());
		param.put("WFIA_ID", activityHistory.getActivityInstanceId());
		param.put("WFIP_ID", activityHistory.getProcessInstanceId());
		param.put("WFIA_CODE", activity.getCode());
		param.put("WFHA_OPERTER", activityHistory.getOperaterId());
		param.put("WFHA_OPERTER_NAME", activityHistory.getOperaterName());
		param.put("WFHA_OPERTE_TIME", new Timestamp(new Date().getTime()));
		param.put("WFHA_CONTENT", activityHistory.getContent());
		param.put("WFHA_ATTRIBUTES", activityHistory.getWorkAttributes().toXML());
	}
	private void packProcessHistoryParam(DataParam param,ProcessHistory processHistory){
		Process process = processHistory.getProcess();
		param.put("WFHP_ID", processHistory.getId());
		param.put("WFIP_ID", processHistory.getProcessInstanceId());
		param.put("WF_ID", process.getId());
		param.put("WFHP_TITLE", processHistory.getTitle());
		param.put("WFHP_LANCHER_ID", processHistory.getLaucherId());
		param.put("WFHP_LANCHER_NAME", processHistory.getLaucherName());
		param.put("WFHP_LANCH_TIME", DateTimeUtil.getDate(processHistory.getLaucheTime()));
		param.put("WFHP_COMPLETER_ID", processHistory.getCompleterId());
		param.put("WFHP_COMPLETER_NAME", processHistory.getCompleterName());
		param.put("WFHP_COMPLETER_TIME", DateTimeUtil.getDate(processHistory.getCompleteTime()));
		param.put("WFHP_COMPLETER_MODE", processHistory.getCompleteMode());
		param.put("WFHP_BUSINESS_ID", processHistory.getBusinessId());
	}
	public DaoHelper getDaoHelper() {
		return daoHelper;
	}
	public void setDaoHelper(DaoHelper daoHelper) {
		this.daoHelper = daoHelper;
	}
	public DefineService getDefineService() {
		return defineService;
	}
	public void setDefineService(DefineService defineService) {
		this.defineService = defineService;
	}
	public void initialize() {
		if (!inited){
			List<Process> processList = this.defineService.findAllProcess();
			for (int i=0;i < processList.size();i++){
				Process process = processList.get(i);
				if (BPMConstants.ProcessStatus.RELEASED.equals(process.getStatus())){
					String processId = process.getId();
					this.registryProcess(processId, process);					
				}
			}
			inited = true;
		}
	}

	public void deleteInstanceAndHistorys(String processURI, String bizRecordId) throws RunningException {
		String msgPrefix = "deleteInstanceAndHistorys() - ";
		loger.debug(msgPrefix + "-----START");
		
		String sqlNameSpace = "WF_INST_PROCESS";
		DataParam param = new DataParam();
		param.put("WFP_ID",processURI);
		param.put("WFIP_BUSINESS_ID",bizRecordId);
		DataRow row = this.daoHelper.getRecord(sqlNameSpace+".findInstanceByDefineIdAndBizId", param);
		if (!MapUtil.isNullOrEmpty(row)){
			String procesIntanceId = row.stringValue("WFIP_ID");
			sqlNameSpace = "WF_INST_ACTIVITY";
			param.put("WFIP_ID",procesIntanceId);
			this.daoHelper.deleteRecords(sqlNameSpace+".deleteActivityInstancesByProcInstId", param);

			sqlNameSpace = "WF_INST_ACTIVITY";
			this.daoHelper.deleteRecords(sqlNameSpace+".deletetWorkItemByProcInstId", param);
			
			sqlNameSpace = "WF_INST_VARIABLE";
			this.daoHelper.deleteRecords(sqlNameSpace+".deleteProcVarInstance", param);
			
			sqlNameSpace = "WF_INST_PROCESS";
			this.daoHelper.deleteRecords(sqlNameSpace+".deleteProcessInstance", param);
			
			sqlNameSpace = "WF_HIS_ACTIVITY";
			this.daoHelper.deleteRecords(sqlNameSpace+".deleteActivityHistoryByProcInstId", param);
			
			sqlNameSpace = "WF_HIS_PROCESS";
			this.daoHelper.deleteRecords(sqlNameSpace+".deleteProcessHistoryByProcInstId", param);			
		}
		
		loger.debug(msgPrefix + "-----END");
	}
	
	private ActivityHistory packActivityHistory(Activity activity,
			String activityInstanceId,ProcessInstance processInstance,WorkAttributes workAttributes){
		String msgPrefix = "BaseEngine::buildActivityHistroy() - ";
		loger.debug(msgPrefix + "-----START");
		
		ActivityHistory result = new ActivityHistory();
		result.setActivity(activity);
		result.setActivityInstanceId(activityInstanceId);
		result.setProcessInstanceId(processInstance.getId());
		result.setOperaterId(processInstance.getOperaterId());
		result.setOperaterName(processInstance.getOperaterName());
		result.setOperateTime(processInstance.getOperateTime());
		String operaDesc = workAttributes.getAttributes().get(WorkAttributes.OPERA_DESC_KEY);
		result.setContent(operaDesc);
		result.setWorkAttributes(workAttributes);
		loger.debug(msgPrefix + "-----END");
		return result;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private List<ActivityInstance> evaluateNextActivityInstances(ProcessInstance processInstance
			,String fromActId,WorkAttributes workAttributes){
		Process process = processInstance.getProcess();
		List<ActivityInstance> result = new ArrayList<ActivityInstance>();
		List<Transition> transitionList = process.getTransitionList();
		for (int i=0;i < transitionList.size();i++){
			Transition transition = transitionList.get(i);
			Activity fromActivity = transition.getFromActivity(); 
			if (fromActId.equals(fromActivity.getId())){
				Activity activity = transition.getToActivity();
				
				String transType = transition.getTransType();
				ActivityInstance activityInstance = null;
				if (Transition.TransType.auto.equals(transType)){
					activityInstance = buildActivityInstance(processInstance,activity,workAttributes);
				}
				else if (Transition.TransType.cond.equals(transType)){
					String expession = transition.getExpression();
					HashMap<String, ProcessVariableInstance> varInstMap = processInstance.getVariableInstances();
					
					if (!StringUtil.isNullOrEmpty(expession)){
						if (!(expession.startsWith("@{") && expession.endsWith("}"))){
							expession = "@{"+expession+"}";
						}
					}
					
					HashMap vars = new HashMap();
					Iterator<String> iter = varInstMap.keySet().iterator();
					while (iter.hasNext()){
						String key = iter.next();
						ProcessVariableInstance variableInstance = varInstMap.get(key);
						String value = variableInstance.getValue();
						vars.put(key, value);
					}
					
					Boolean flag = (Boolean)TemplateRuntime.eval(expession, vars);
					if (flag){
						activityInstance = buildActivityInstance(processInstance,activity,workAttributes);	
					}
				}
				
				if (activityInstance != null){
					result.add(activityInstance);					
				}
			}
		}
		return result;
	}

	private ActivityInstance buildActivityInstance(ProcessInstance processInstance,Activity activity
			,WorkAttributes workAttributes){
		ActivityInstance result = new ActivityInstance();
		result.setActivity(activity);
		result.setProcessInstance(processInstance);
		result.setName(activity.getName());
		
		if (activity.isKeepLastPerformer()){
			List<ActivityHistory> activityHistoryList = processInstance.getActivityHistorys();
			for (int i=0;i < activityHistoryList.size();i++){
				ActivityHistory activityHistory = activityHistoryList.get(i);
				String hisActivityCode = activityHistory.getActivity().getCode();
				if (hisActivityCode.equals(activity.getCode())){
					String operaterId = activityHistory.getOperaterId();
					result.getOperaterIdList().add(operaterId);
					break;
				}
			}
		}
		return result;
	}

	private void executeInterceporList(ActivityInstance activityInstance,List<BaseInterceptor> interceptorList,WorkAttributes workAttributes){
		if (interceptorList != null){
			for (int i=0;i < interceptorList.size();i++){
				BaseInterceptor interceptor = interceptorList.get(i);
				try {
					interceptor.doIntercept(activityInstance);					
				} catch (Exception e) {
					interceptor.handleException(activityInstance,e);
				}
			}
		}
	}

	@Override
	public DataRow findUserRow(String seqId,String type) {
		String statementId = "SecurityGroup8Associates.getSecurityUserRecord";
		DataParam param = new DataParam();
		if (UserSeqType.USER_ID.equals(type)){
			param.put("USER_ID",seqId);			
		}else{
			param.put("USER_CODE",seqId);
		}
		DataRow row = this.daoHelper.getRecord(statementId, param);
		return row;
	}
	
	public DataRow findWorkItemRow(String processInstId,String userCode,String activityCode){
		DataRow result = null;
		String statementId = "WF_INST_PROCESS.findWorkItemRow";
		DataParam param = new DataParam("processInstId",processInstId,"activityCode",activityCode,"userCode",userCode);
		result = this.daoHelper.getRecord(statementId, param);
		return result;
	}

	public void updateWorkItem(String processInstId,String activityInstId,String userId,String delegateeId){
		DataParam param = new DataParam();
		String statementId = "WF_INST_PROCESS.updateWorkItem";

		param.put("WFIP_ID",processInstId);
		param.put("WFIA_ID",activityInstId);
		param.put("USER_ID",userId);
		param.put("NEW_USER_ID",delegateeId);
		this.daoHelper.updateRecord(statementId, param);
	}
	
	@Override
	public String findCurrentProcessId(String processCode) {
		String result = null;
		String statementId = "WF_INST_PROCESS.findCurrentProcessId";
		DataParam param = new DataParam("WFP_CODE",processCode);
		List<DataRow> records = this.daoHelper.queryRecords(statementId, param);
		if (records != null && records.size() > 0){
			DataRow row = records.get(0);
			result = row.getString("WFP_ID");
		}
		return result;
	}
	
	public void insertProcessLog(ProcessInstance processInstance,String actionType,String actionUser,String actionInstId,String descrption){
		DataParam param = new DataParam();
		String statementId = "WF_LOG_PROCESS.insertLog";

		String primaryKey = KeyGenerator.instance().genKey();
		param.put("WFLP_ID",primaryKey);
		param.put("WFIP_ID",processInstance.getId());
		param.put("WFLP_TYPE",actionType);
		param.put("WFLP_ACTION_USER",actionUser);
		param.put("WFLP_ACTION_TIME",new Date());
		param.put("WFLP_ACTION_OJB",actionInstId);
		param.put("WFLP_ACTION_DESC",descrption);
		this.daoHelper.insertRecord(statementId, param);
	}

	@Override
	public void saveDraft(String processId, String userId, String bizRecordId,String bizTitle)
			throws RunningException {
		DataParam param = new DataParam();
		param.put("WFP_ID",processId);
		param.put("WWD_BIZ_ID",bizRecordId);
		
		String statementId = "WF_WORK_DRAFT.retrieveWorkDraft";
		DataRow record = this.daoHelper.getRecord(statementId, param);
		if (record != null && record.size() > 0){
			statementId = "WF_WORK_DRAFT.updateWorkDraft";
			param.put("WWD_BIZ_TITLE",bizTitle);
			param.put("WWD_MODIFIER",userId);
			param.put("WWD_MODIFY_TIME",new Date());
			this.daoHelper.updateRecord(statementId, param);
		}else{
			statementId = "WF_WORK_DRAFT.insertWorkDraft";
			String primaryKey = KeyGenerator.instance().genKey();
			param.put("WWD_ID",primaryKey);
			param.put("WWD_BIZ_TITLE",bizTitle);
			param.put("WWD_CREATER",userId);
			param.put("WWD_CREATE_TIME",new Date());
			this.daoHelper.insertRecord(statementId, param);
		}
	}
}